#ifndef RAY_TRACE_PRO_RAY_TRACE_SYSTEM_H
#define RAY_TRACE_PRO_RAY_TRACE_SYSTEM_H

#include "stdafx.h"
#include "VectorMath.h"
#include "CL/cl.hpp"
#include "BatchedKernelFunctor.h"
#include "Debug.h"

namespace RayTracePro
{
	class Scene;
	class Material;
	template <typename T>
	class DeviceList;
	enum class PlatformVendor
	{
		Unkown, NVidia, AMD, Intel
	};

	class GpuDevice
	{
	private:
		static bool initialized;
		static int MaxGlobalWorkItems;
		static int scan_WorkGroupSize;
		static cl::Kernel intScanKernel;
		
		static cl::Context context;
		static cl::CommandQueue queue;
		static cl::Program program;
		static cl::Device device;
		static GxLibBasic::String GenerateKernelSources(PlatformVendor vendor, cl_device_type deviceType);
	public:
		static void Initialize();
		static void Finalize();
		static void Finish();
		static void Barrier();
		static void AllocScanList(DeviceList<int> & list, int size);
		static cl::CommandQueue GetQueue();
		static cl::Context GetContext();
		static cl::Kernel CreateKernel(char * kernelName);
		static cl::KernelFunctor InvokeKernel(cl::Kernel & kernel, cl::NDRange global, cl::NDRange local);
		static BatchedKernelFunctor InvokeKernel(cl::Kernel & kernel, int globalSize, int localSize, int batchSize = 0);
		static cl::Event ExclusiveScan(const cl::Buffer & buffer, int offset, int size);
		static void ExclusiveScan(const cl::Buffer & bufferOut, const cl::Buffer & bufferIn, int size);
		static MultipleWaitHandle RadixSortInt4(const cl::Buffer & buffer);
	};

	class RayTraceSystem : public GxLibBasic::Object
	{
	private:
		GxLibBasic::Array<GxLibBasic::RefPtr<DebugTimming>> debugCounters;
	public:
		float GeometryBias;
		int AntiAliasSamples;
		RayTraceSystem();
		Scene * CreateScene();
		Material * CreateMaterial();
		
		void InitRenderThread();
		void FinalizeRenderThread();
		void StartBenchmark(const char * name);
		void StopBenchmark();
	};
}

#endif